package org.xiaov.lunasql.spring.proxy;

import org.apache.ibatis.builder.SqlSourceBuilder;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.xiaov.lunasql.engine.common.util.LunaJdbcUtils;
import org.xiaov.lunasql.engine.config.LunaSqlConfig;
import org.xiaov.lunasql.engine.transform.TransformManager;
import org.xiaov.lunasql.spring.mybatis.DatabaseTypeHolder;
import org.xiaov.lunasql.spring.mybatis.MyBatisTransformHolder;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * The type Connection proxy.
 *
 * @author xiaovcloud
 * @since 2024/1/23 10:50
 */
public class LunaConnectionProxy extends AbstractConnectionProxy {

    private final LunaSqlConfig lunaConfig;
    private static final Log log = LogFactory.getLog(LunaConnectionProxy.class);

    /**
     * Instantiates a new Connection proxy.
     *
     * @param targetConnection    the target connection
     * @param lunaConfig          lunaConfig
     */
    public LunaConnectionProxy(Connection targetConnection,
                               LunaSqlConfig lunaConfig) {
        super(targetConnection);
        this.lunaConfig = lunaConfig;
        try {
            String url = targetConnection.getMetaData().getURL();
            String dbType = LunaJdbcUtils.getDbType(url);
            DatabaseTypeHolder.setDbType(dbType);
        } catch (SQLException e) {
            throw new IllegalStateException("不能获取数据库类型", e);
        }
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        sql = transformSQL(sql);
        PreparedStatement preparedStatement = getTargetConnection().prepareStatement(sql);
        return new LunaPreparedStatementProxy(this, preparedStatement, sql, lunaConfig);
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        sql = transformSQL(sql);
        return targetConnection.prepareCall(sql);
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        sql = transformSQL(sql);
        return targetConnection.nativeSQL(sql);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
                                              int resultSetHoldability) throws SQLException {
        sql = transformSQL(sql);
        PreparedStatement preparedStatement = targetConnection.prepareStatement(sql, resultSetType,
                resultSetConcurrency, resultSetHoldability);
        return new LunaPreparedStatementProxy(this, preparedStatement, sql, lunaConfig);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
                                         int resultSetHoldability) throws SQLException {
        sql = transformSQL(sql);
        return targetConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        sql = transformSQL(sql);
        PreparedStatement preparedStatement = targetConnection.prepareStatement(sql, autoGeneratedKeys);
        return new LunaPreparedStatementProxy(this, preparedStatement, sql, lunaConfig);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        sql = transformSQL(sql);
        PreparedStatement preparedStatement = targetConnection.prepareStatement(sql, columnIndexes);
        return new LunaPreparedStatementProxy(this, preparedStatement, sql, lunaConfig);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        sql = transformSQL(sql);
        PreparedStatement preparedStatement = targetConnection.prepareStatement(sql, columnNames);
        return new LunaPreparedStatementProxy(this, preparedStatement, sql, lunaConfig);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
            throws SQLException {
        sql = transformSQL(sql);
        PreparedStatement preparedStatement = targetConnection.prepareStatement(sql, resultSetType,
                resultSetConcurrency);
        return new LunaPreparedStatementProxy(this, preparedStatement, sql, lunaConfig);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        sql = transformSQL(sql);
        return targetConnection.prepareCall(sql, resultSetType, resultSetConcurrency);
    }

    /**
     * 转换sql
     *
     * @param sql 需要转换的sql
     * @return 转换结果
     */
    protected String transformSQL(String sql) {
        if (MyBatisTransformHolder.get()) {
            //已经处理过了，不用再处理
            return sql;
        }
        String result = TransformManager.INSTANCE.parseSQL(sql, DatabaseTypeHolder.getDbType());
        if (log.isDebugEnabled()) {
            log.debug("==>  Transform: " + SqlSourceBuilder.removeExtraWhitespaces(result));
        }
        return result;
    }
}
